package com.ruoyi.back.service.impl

import cn.hutool.core.bean.BeanUtil
import cn.hutool.core.util.RandomUtil
import cn.hutool.core.util.StrUtil
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
import com.ruoyi.app.common.*
import com.ruoyi.back.domain.AppUser
import com.ruoyi.back.domain.dto.AppUserDto
import com.ruoyi.back.domain.dto.UserListSearchDto
import com.ruoyi.back.domain.vo.*
import com.ruoyi.back.enums.NoticeTypeEnum
import com.ruoyi.back.enums.UserStatusEnum
import com.ruoyi.back.enums.UserTypeEnum
import com.ruoyi.back.mapper.AppUserMapper
import com.ruoyi.back.service.AppUserService
import com.ruoyi.back.service.UserMemberMessageService
import com.ruoyi.back.service.UserMemberService
import com.ruoyi.back.service.UserRecordService
import com.ruoyi.common.core.page.TableSupport
import com.ruoyi.common.utils.bean.BeanUtils
import com.ruoyi.socket.WebSocketServer
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.*

@Service
class AppUserServiceImpl : ServiceImpl<AppUserMapper, AppUser>(), AppUserService {

    @Autowired
    private lateinit var userMemberService: UserMemberService

    @Autowired
    private lateinit var userRecordService: UserRecordService

    @Autowired
    private lateinit var userMemberMessageService: UserMemberMessageService


    override fun operationUser(appUserDto: AppUserDto): AppUser =
        getOne(
            KtQueryWrapper(AppUser::class.java)
                .eq(AppUser::username, appUserDto.username)
                .eq(AppUser::loginType, appUserDto.loginType)
        )
            ?.let {
                val pass = it.password
                val firstInstallationDataOld = it.firstInstallationData
                it.apply {
                    BeanUtils.copyProperties(appUserDto, this)
                    password = pass
                    lastLoginDate = Date()
                    firstInstallationData = firstInstallationDataOld ?: appUserDto.firstInstallationData
                }.also { updateById(it) }

            }
            ?: kotlin.run {
                AppUser().apply {
                    BeanUtils.copyProperties(appUserDto, this)
                    userId = RandomUtil.randomNumbers(6)
                    registerDate = Date()
                    lastLoginDate = Date()
                }.also {
                    save(it)
                    userMemberMessageService.sendUserMessage(NoticeTypeEnum.USER_REGISTER, it.id!!)
                    WebSocketServer.sendMessage(it.id)
                }
            }

    override fun selectUserByUserId(userId: String): AppUser? =
        getOne(KtQueryWrapper(AppUser::class.java).eq(AppUser::userId, userId))

    override fun getAppUserIdByUserType(userType: UserTypeEnum?): List<Long>? =
        list(KtQueryWrapper(AppUser::class.java).eq(userType != null, AppUser::userType, userType?.code))
            .takeIf { it.isNotEmpty() }
            ?.run { map { it.id!! } }


    override fun selectAppUserList(userListSearchDto: UserListSearchDto): Page<UserListVo> {

        return TableSupport.buildPageRequest().let { pageDomain ->

            page(
                Page(pageDomain.pageNum.toLong(), pageDomain.pageSize.toLong()), KtQueryWrapper(AppUser::class.java)
                    .eq(
                        StrUtil.isNotBlank(userListSearchDto.searchParam),
                        AppUser::username,
                        userListSearchDto.searchParam
                    )
                    .or().eq(
                        StrUtil.isNotBlank(userListSearchDto.searchParam),
                        AppUser::userId,
                        userListSearchDto.searchParam
                    )
                    .eq(userListSearchDto.userStatus != null, AppUser::status, userListSearchDto.userStatus)
                    .eq(StrUtil.isNotBlank(userListSearchDto.source), AppUser::source, userListSearchDto.source)
                    .eq(userListSearchDto.userType != null, AppUser::userType, userListSearchDto.userType)
                    .eq(userListSearchDto.loginType != null, AppUser::loginType, userListSearchDto.loginType)
                    .orderByDesc(AppUser::registerDate)
            )
                .let { appUserPage ->
                    appUserPage.records.takeIf { it.isNotEmpty() }?.run {
                        forEach { updateById(it.apply { userType = userMemberService.userMemberType(it.id!!).code }) }
                    }
                    Page<UserListVo>().apply {
                        BeanUtil.copyProperties(appUserPage, this)
                        records = appUserPage.records.takeIf { it.isNotEmpty() }
                            ?.run {
                                map {
                                    UserListVo().apply {
                                        BeanUtil.copyProperties(it, this)
                                        userType = it.userType?.userType()
                                        userTypeCode = it.userType
                                        loginType = it.loginType?.loginType()
                                        registerDate = it.registerDate?.format()
                                        lastLoginDate = it.lastLoginDate?.format()
                                        totalChangeFaceCount = it.totalChangeFaceCount?.toLong()
//                                        changeFaceNum = userRecordService.getUserChangeFaceNum(it.id!!)
                                        changeFaceNum = ((it.changeFaceRemainCount ?: 0).takeIf {
                                            it > (totalChangeFaceCount ?: 0).toInt()
                                        }
                                            ?.run { totalChangeFaceCount } ?: (it.changeFaceRemainCount
                                            ?: 0).toLong()) + (it.singleChangeFaceCount ?: 0)
                                        retainChangeFaceNum =
                                            ((it.totalChangeFaceCount ?: 0) - (changeFaceNum ?: 0)).let {
                                                it.takeIf { it >= 0 }?.run { it } ?: 0
                                            }
                                        memberDate = userMemberService.getUserMemberByUserId(it.id!!)
                                            ?.run { "${beginMemberDate?.format()}至${endMemberDate?.format()}" } ?: "--"
                                    }
                                }
                            }
                    }
                }
        }

    }

    override fun appUserInfo(userId: Long): UserInfo? =
        getById(userId)?.let {
            UserInfo().apply {
                BeanUtil.copyProperties(it, this)
                userType = it.userType?.userType()
                loginType = it.loginType?.loginType()
                changeFaceNum = userRecordService.getUserChangeFaceNum(it.id!!)
                memberDate = userMemberService.getUserMemberByUserId(it.id!!)
                    ?.run { "${beginMemberDate?.format()}至${endMemberDate?.format()}" } ?: "--"
            }
        }

    override fun userChangeFaceDetail(userId: Long): Data<UserChangeFaceDetailVo> =
        getById(userId)?.let {
            Ok("获取用户换脸详情成功", UserChangeFaceDetailVo().apply {
                BeanUtil.copyProperties(it, this)
                videoFaceNum = userRecordService.getUserChangeFaceNum(userId, 2)
                picFaceNum = userRecordService.getUserChangeFaceNum(userId, 3)
            })
        } ?: kotlin.run {
            Fail("暂无该用户")
        }

    override fun userChangeFaceResource(resourceSearchDto: ResourceSearchDto): PageData<ResourceInfos> =
        TableSupport.buildPageRequest().let {
            userRecordService.getUserResourceRecordPage(resourceSearchDto.apply { pageDomain = it })
        }

    override fun removeUserChangeFaceResource(ids: String): Data<Boolean> =
        Ok("移除换脸资源成功", userRecordService.removeByIds(ids.split(",")))

    override fun freezeAppUser(userId: Long): Data<Boolean> =
        getById(userId)?.run {
            Ok("更新用户状态成功", updateById(apply {
                status = when (status) {
                    UserStatusEnum.NORMAL.code -> UserStatusEnum.FREEZE.code
                    else -> UserStatusEnum.NORMAL.code
                }
            }))
        } ?: Fail(201, "不存在当前用户")

    override fun removeAppUser(userIds: String): Data<Boolean> =
        Ok("批量移除成功", removeByIds(userIds.split(",")))

    override fun cancelMember(userId: Long): Data<Boolean> {
        getById(userId)?.run {
            updateById(this.apply {
                userType = UserTypeEnum.NORMAL.code
                changeFaceRemainCount = 0
            })
        }
        return Ok("移除用户会员成功", userMemberService.removeUserMember(userId))
    }
}